package classfile

type AttributeInfo interface {
	readInfo(reader *ClassReader)
}

func readAttCount(reader *ClassReader) uint16 {
	attributesCount := reader.readUint16()
	return attributesCount
}

// 读取属性表
func readAttributes(reader *ClassReader, cp ConstantPool, attributesCount uint16) []AttributeInfo {
	attributes := make([]AttributeInfo, attributesCount)
	for i := range attributes {
		attributes[i] = readAttribute(reader, cp)
	}
	return attributes
}

// 读取单个属性
func readAttribute(reader *ClassReader, cp ConstantPool) AttributeInfo {
	attrNameIndex := reader.readUint16()
	attrName := cp.getUtf8(attrNameIndex)
	attrLen := reader.readUint32()
	attrInfo := newAttributeInfo(attrName, attrLen, cp)
	attrInfo.readInfo(reader)
	return attrInfo
}

// 创建具体属性实例
// todo 属性不完善，补充！
func newAttributeInfo(attrName string, attrLen uint32, cp ConstantPool) AttributeInfo {
	switch attrName {
	// Java代码编译成的字节码指令
	case "Code":
		return &CodeAttribute{cp: cp}
	// 由 final关键字定义的常量值
	case "ConstantValue":
		return &ConstantValueAttribute{}
	/*
		A run-time interpreter or tool that reads the class file format,
		such as a compiler,
		can use this marking to advise the user that a superseded class,
		interface, method, or field is being referred to.
		The presence of a Deprecated attribute does not
		alter the semantics of a class or interface.
	*/
	case "Deprecated":
		return &DeprecatedAttribute{}
	case "Exceptions":
		return &ExceptionsAttribute{}
	case "InnerClass":
		return &InnerClassesAttribute{}
	// 描述Java源码行号和字节码行号(字节码偏移量)之间的关系
	case "LineNumberTable":
		return &LineNumberTableAttribute{}
	case "LocalVariableTable":
		return &LocalVariableTableAttribute{}
	case "SourceFile":
		return &SourceFileAttribute{cp: cp}
	case "Synthetic":
		return &SyntheticAttribute{}
	case "Signature":
		return &SignatureAttribute{}
	case "LocalVariableTypeTable":
		return &LocalVariableTypeTableAttribute{}
	case "BootstrapMethods":
		return &BootstrapMethodsAttribute{}
	case "MethodParameters":
		return &MethodParametersAttribute{}
	default:
		return &UnparsedAttribute{attrName, attrLen, nil}
	}
}
